/*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
*
*
* Authors:                  zhoujian
* Email:            343600434@qq.com
* Date:         Feb-18-2024 16:33:22
*
*/

#include "gd32l23x.h"
#include "gd32l233r_eval.h"

#include "ds3231.h"

#include <stdio.h>

//#define DEBUG_PRINTF
DS3231_zTypeDef ds3231_state;

DS3231_CALENDAR_T calendar;
uint8_t two_min_start_min;
uint8_t two_min_start_sec;
uint8_t two_min_min;
uint8_t two_min_sec;
volatile uint8_t show_time_update;
volatile uint8_t time_end;
volatile uint8_t no_rtc;
unsigned char BCD2HEX(unsigned char val)
{
    unsigned char i;
    i = val & 0x0f;
    val >>= 4;
    val &= 0x0f;
    val *= 10;
    i += val;
    return i;
}

unsigned short B_BCD(unsigned char val)
{
    unsigned char i, j, k;
    i = val / 10;
    j = val % 10;
    k = j + (i << 4);
    return k;
}




void i2c_Delay()
{
    uint32_t volatile i, j;

    //for(i=1; i > 0; i--) {//10us
    for(j = 1; j > 0; j--);

    //  }
}

uint32_t I2C_SDA_READ()
{
    volatile uint32_t t = 0, j = 252;
    I2C_SDA_INPUT;

    while(--j > 0) {
        if(!IS_I2C_SDA_H) {
            t++;

            if(t == 3) {
                break;
            }

        } else {
            t = 0;
        }
    }

    I2C_SDA_OUTPUT;
    return j;
}

void i2c_Start(void)
{
    I2C_SDA_H;
    I2C_SCL_H;
    i2c_Delay();
    I2C_SDA_L;
    i2c_Delay();
    I2C_SCL_L;
    //i2c_Delay();
}
void i2c_Stop(void)
{
    I2C_SDA_L;
    I2C_SCL_H;
    i2c_Delay();
    I2C_SDA_H;
}
void i2c_SendByte(uint8_t _ucByte)
{
    unsigned char i;

    //  I2C_SCL = 0;    //起始信号已经拉低了，无需重复
    for(i = 0; i < 8; i ++) {
        if(_ucByte & (0x80 >> i)) { //把Byte最高位取出，赋值给I2C_SDA,依次从高到底
            I2C_SDA_H;

        } else {
            I2C_SDA_L;
        }

        i2c_Delay();
        I2C_SCL_H;
        i2c_Delay();
        //      _nop_();_nop_();_nop_();_nop_();_nop_();//需要0.4us
        I2C_SCL_L;
        i2c_Delay();
    }
}


uint8_t i2c_ReadByte(void)
{
    unsigned char i, Byte = 0x00;
    //I2C_SDA_H;    //接收之前，先把I2C_SDA置1，释放总线
    I2C_SDA_INPUT;
    i2c_Delay();

    for(i = 0; i < 8; i++) {
        I2C_SCL_H;  //拉高SCL，SCL读取SDA
        i2c_Delay();

        if(IS_I2C_SDA_H) {
            Byte |= (0x80 >> i);
        }

        /*如果读取到的SDA为1，把Byte最高位置1，如果读取到的SDA为0，不处理，默认最高位为0，放在循环里从高位到低位依次读取*/
        I2C_SCL_L;  //拉低SCL，结束当前循环
        i2c_Delay();
    }

    I2C_SDA_OUTPUT;
    return Byte;
}

uint8_t i2c_WaitAck(void)
{
    uint8_t re;
    I2C_SDA_H;    /* CPU释放SDA总线 */
    i2c_Delay();
    I2C_SCL_H;   /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
    i2c_Delay();
    //i2c_Delay();
    //i2c_Delay();
    //i2c_Delay();
    re = I2C_SDA_READ();/* CPU读取SDA口线状态 */
    /*if (I2C_SDA_READ())
    {
        re = 1;
    }
    else
    {
        re = 0;
    }*/
    I2C_SCL_L;
    //i2c_Delay();
    return re;
}


/*
*********************************************************************************************************
*    函 数 名: i2c_Ack
*    功能说明: CPU产生一个ACK信号
*    形    参：无
*    返 回 值: 无
*********************************************************************************************************
*/
void i2c_Ack(void)
{
    I2C_SDA_L;    /* CPU驱动SDA = 0 */
    i2c_Delay();
    I2C_SCL_H;    /* CPU产生1个时钟 */
    i2c_Delay();
    I2C_SCL_L;
    i2c_Delay();
    I2C_SDA_H;    /* CPU释放SDA总线 */
}


/*
*********************************************************************************************************
*    函 数 名: i2c_NAck
*    功能说明: CPU产生1个NACK信号
*    形    参：无
*    返 回 值: 无
*********************************************************************************************************
*/
void i2c_NAck(void)
{
    I2C_SDA_H;    /* CPU驱动SDA = 1 */
    i2c_Delay();
    I2C_SCL_H;    /* CPU产生1个时钟 */
    i2c_Delay();
    I2C_SCL_L;
    i2c_Delay();
}

void ds3231_byte_write(unsigned char Waddr, unsigned char Data)
{
    //向任意地址写入一个字节数据函数
    i2c_Start();//产生起始信号
    i2c_SendByte(0xD0);//写入设备地址（写）
    i2c_Ack();//等待设备的应答.
    i2c_SendByte(Waddr);//写入要操作的单元地址。
    i2c_Ack();//等待设备的应答。
    i2c_SendByte(Data);//写入数据。
    i2c_Ack();//等待设备的应答。
    i2c_Stop();//产生停止符号。
}
//-------------------------------------------------------------------
unsigned char ds3231_byte_read(unsigned char Waddr)
{
    //从任意地址读取一个字节数据函数
    unsigned char Data;//定义一个缓冲寄存器。
    i2c_Start();//产生起始信号
    i2c_SendByte(0xD0);//写入设备地址（写）
    i2c_Ack();//等待设备的应答
    i2c_SendByte(Waddr);//写入要操作的单元地址。
    i2c_Ack();//等待设备的应答。
    i2c_Start();//产生起始信号
    i2c_SendByte(0xD1);//写入设备地址（写）
    i2c_Ack();//等待设备的应答
    Data = i2c_ReadByte();
    i2c_NAck();
    i2c_Stop();//产生停止符号。
    //-------------------返回读取的数据--------------------
    return Data;//返回读取的一个字节数据。
}
void Read_RTC(void)
{
    calendar.year = ds3231_byte_read(0x06);
    calendar.mon = ds3231_byte_read(0x05);
    calendar.mday = ds3231_byte_read(0x04);
    calendar.hour = ds3231_byte_read(0x02);
    calendar.min = ds3231_byte_read(0x01);
    calendar.sec = ds3231_byte_read(0x00);
}
void Set_RTC(unsigned char yea, unsigned char mon, unsigned char da, unsigned char hou, unsigned char min, unsigned char sec)
{
    unsigned char temp = 0;
    temp = B_BCD(yea);
    ds3231_byte_write(0x06, temp);
    temp = B_BCD(mon);
    ds3231_byte_write(0x05, temp);
    temp = B_BCD(da);
    ds3231_byte_write(0x04, temp);
    temp = B_BCD(hou);
    ds3231_byte_write(0x02, temp);
    temp = B_BCD(min);
    ds3231_byte_write(0x01, temp);
    temp = B_BCD(sec);
    ds3231_byte_write(0x00, temp);
}
uint8_t get_show_time(void)
{
    static uint8_t pre_sec;
    calendar.year = ds3231_byte_read(0x06);
    calendar.year = BCD2HEX(calendar.year);
    calendar.mon = ds3231_byte_read(0x05);
    calendar.mon = BCD2HEX(calendar.mon);
    calendar.mday = ds3231_byte_read(0x04);
    calendar.mday = BCD2HEX(calendar.mday);
    calendar.hour = ds3231_byte_read(0x02);
    calendar.hour &= 0x3f;
    calendar.hour = BCD2HEX(calendar.hour);
    calendar.min = ds3231_byte_read(0x01);
    calendar.min = BCD2HEX(calendar.min);
    calendar.sec = ds3231_byte_read(0x00);
    calendar.sec = BCD2HEX(calendar.sec);

    if(pre_sec != calendar.min) {
        pre_sec = calendar.min;
        show_time_update = 1;
        return 1;
    }

    return 0;
}

void ds3231_get_2min_start()
{
    two_min_start_min = ds3231_byte_read(0x01);
    two_min_start_min = BCD2HEX(two_min_start_min);
    two_min_start_sec = ds3231_byte_read(0x00);
    two_min_start_sec = BCD2HEX(two_min_start_sec);

    if(two_min_start_sec == 165) {
        if(two_min_start_min == 165) {
            two_min_start_sec = 0;
            two_min_start_min = 0;
            no_rtc = 1;
        }

    } else {
        no_rtc = 0;
    }

    time_end = 0;
}

uint8_t ds3231_is_2min_end()
{
    uint8_t temp_min, temp_sec;
    static uint8_t sec = 0;

    if(time_end) {
        return 1;
    }

    two_min_min = ds3231_byte_read(0x01);
    two_min_min = BCD2HEX(two_min_min);
    two_min_sec = ds3231_byte_read(0x00);
    two_min_sec = BCD2HEX(two_min_sec);

    if(two_min_sec == 165) {
        if(two_min_min == 165) {
            no_rtc = 1;

            if(sec++ >= 15) {
                return 1;

            } else {
                return 0;
            }
        }

    } else {
        no_rtc = 0;
    }

#ifdef DEBUG_PRINTF
    log_debug("%d:%d ---> %d:%d\n", two_min_start_min, two_min_start_sec, two_min_min, two_min_sec);
#endif

    //if(two_min_start_min+2<two_min_min)
    if(two_min_min >= two_min_start_min) {
        temp_min = two_min_min - two_min_start_min;

    } else {
        temp_min = 60 -  two_min_start_min + two_min_min ;
    }

    if(two_min_sec >= two_min_start_sec) {
        temp_sec = two_min_sec - two_min_start_sec;

    } else {
        temp_sec = 60 -  two_min_start_sec + two_min_sec ;
        temp_min--;
    }

    if((temp_min >= 0) && (temp_sec >= 15)) {
        return 1;
    }

    return 0;
}


void ds3231_init(void)
{
    //ds3231_state = DS3231_State_0x00;
    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP,  GPIO_PIN_12);
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,  GPIO_PIN_11);
    //gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
    I2C_SDA_H;
    I2C_SCL_H;
    ds3231_byte_write(0xE, 0);
    ds3231_byte_write(0xF, 0);
    //Set_RTC(24,2,28,17,58,06);
    ds3231_get_2min_start();
}

uint8_t ds3231_test()
{
    uint8_t v[0x13];
    i2c_Start();
    i2c_SendByte(0xD0);
    i2c_WaitAck();
    i2c_SendByte(0x00);
    i2c_WaitAck();
    i2c_Start();
    i2c_SendByte(0xD1);
    i2c_WaitAck();
    //i2c_SendByte(0x0f);
    //v = i2c_WaitAck();
    v[0] = i2c_ReadByte();
    i2c_Ack();
    v[1] = i2c_ReadByte();
    i2c_Ack();
    v[2] = i2c_ReadByte();
    i2c_Ack();
    v[3] = i2c_ReadByte();
    i2c_Ack();
    v[4] = i2c_ReadByte();
    i2c_Ack();
    v[5] = i2c_ReadByte();
    i2c_Ack();
    v[6] = i2c_ReadByte();
    i2c_Ack();
    v[7] = i2c_ReadByte();
    i2c_Ack();
    v[8] = i2c_ReadByte();
    i2c_Ack();
    v[9] = i2c_ReadByte();
    i2c_Ack();
    v[10] = i2c_ReadByte();
    i2c_Ack();
    v[11] = i2c_ReadByte();
    i2c_Ack();
    v[12] = i2c_ReadByte();
    i2c_Ack();
    v[13] = i2c_ReadByte();
    i2c_Ack();
    v[14] = i2c_ReadByte();
    i2c_Ack();
    v[15] = i2c_ReadByte();
    i2c_Ack();
    v[16] = i2c_ReadByte();
    i2c_Ack();
    v[17] = i2c_ReadByte();
    i2c_Ack();
    v[18] = i2c_ReadByte();
    i2c_NAck();
    //i2c_WaitAck();
    i2c_Stop();
    int i = 0;

    for(i = 0; i < 7; i++) {
        log_debug(" 0x%x", v[i]);
    }

    log_debug("\n");

    for(i = 7; i < 13; i++) {
        log_debug(" 0x%x", v[i]);
    }

    log_debug("\n");

    for(i = 13; i < 19; i++) {
        log_debug(" 0x%x", v[i]);
    }

    log_debug("\n");
    return v[0];
}


void ds3231_read_test()
{
    //ds3231_test();
    get_show_time();
    //Read_RTC();
#ifdef DEBUG_PRINTF
    log_debug("year:%d", calendar.year);
    log_debug("-%d", calendar.mon);
    log_debug("-%d", calendar.mday);
    log_debug(" %d", calendar.hour);
    log_debug(":%d", calendar.min);
    log_debug(":%d\n", calendar.sec);
#endif

    if(ds3231_is_2min_end()) {
        time_end = 1;
#ifdef DEBUG_PRINTF
        log_debug("2min end \n");
#endif
    }
}


